package com.chlitina.store.modules.inventory.web;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.chlitina.store.common.config.Global;
import com.chlitina.store.common.mapper.JsonMapper;
import com.chlitina.store.common.persistence.Page;
import com.chlitina.store.common.utils.DateUtils;
import com.chlitina.store.common.web.BaseController;
import com.chlitina.store.modules.base.entity.StoreProduct;
import com.chlitina.store.modules.base.entity.StoreSelfProduct;
import com.chlitina.store.modules.base.service.CustomerService;
import com.chlitina.store.modules.base.service.StoreCareService;
import com.chlitina.store.modules.base.service.StoreProductService;
import com.chlitina.store.modules.base.service.StoreSelfProductService;
import com.chlitina.store.modules.employee.dao.EmployeeDao;
import com.chlitina.store.modules.employee.entity.Employee;
import com.chlitina.store.modules.expert.entity.Product;
import com.chlitina.store.modules.expert.entity.ProductCategory;
import com.chlitina.store.modules.expert.service.ProductService;
import com.chlitina.store.modules.inventory.dao.InventoryOutDao;
import com.chlitina.store.modules.inventory.entity.StoreInventoryOut;
import com.chlitina.store.modules.inventory.entity.StoreInventoryOutDetail;
import com.chlitina.store.modules.inventory.model.InQuery;
import com.chlitina.store.modules.inventory.model.InventoryOut;
import com.chlitina.store.modules.inventory.model.OutProduct;
import com.chlitina.store.modules.inventory.model.OutQuery;
import com.chlitina.store.modules.inventory.service.InventoryService;
import com.chlitina.store.modules.sys.utils.StoreUtils;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Inventory Controller
 * 
 * @author Songsong.xu
 * @version 2013-11-05
 */
@Controller
@RequestMapping(value = Global.ADMIN_PATH + "/inventory/out")
public class InventoryOutController extends BaseController {
	@Autowired
	private ProductService productService;
	@Autowired
	private StoreCareService storeCareService;
	@Autowired
	private StoreProductService storeProductService;
	@Autowired
	private CustomerService customerService;
	@Autowired
	private EmployeeDao employeeDao;
	@Autowired
	private InventoryOutDao inventoryOutDao;
	@Autowired
	private InventoryService inventoryService;
	@Autowired
	private StoreSelfProductService storeSelfProductService;
	public static int DEFAULT_PAGE_SIZE = 5;
	String KEY_INVENTORY_OUT = "inventoryOut";
	String KEY_OUT_PRODUCT = "outProduct";
	String URI_OUT_SYSTEM_PRODUCT_ADD_EDIT_PAGE = "modules/inventory/outAddEditSystemProductPage";

	@RequestMapping(value = { "" })
	public String inventoryOut(OutQuery outQuery, HttpServletRequest request,
			HttpServletResponse response, Model model) {
		Object out = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		updateEmployee(request);
		model.addAttribute("editInProduct", new OutProduct());
		if (out != null) {// 继续上次录入
			InventoryOut inventoryOut = (InventoryOut) out;
			model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);
			model.addAttribute(KEY_OUT_PRODUCT, new OutProduct());
			Page<OutProduct> page = new Page<OutProduct>(request, response);
			List<OutProduct> products = new ArrayList<OutProduct>();
			products.addAll(inventoryOut.getStoreselfProducts());
			products.addAll(inventoryOut.getSystemProducts());
			page.updatePage(products);
			model.addAttribute("page", page);
			return getURI_out_main();
		} else {// 重新入库,或者
			Page<StoreInventoryOut> page = new Page<StoreInventoryOut>(request,
					response);
			inventoryService.outQuery(page, outQuery);
			model.addAttribute("page", page);
			return "modules/inventory/inventoryOut";
		}
	}

	@RequestMapping(value = { "product/cancel" })
	public String inventoryOutProductCancel(HttpServletRequest request,
			HttpServletResponse response, Model model) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		if (attribute != null) {// for some reason, cancel multiples
			InventoryOut inventoryout = (InventoryOut) attribute;
			inventoryout.getSystemProducts().clear();
			inventoryout.getStoreselfProducts().clear();
			request.getSession().removeAttribute(KEY_INVENTORY_OUT);
		}

		model.addAttribute("outQuery", new OutQuery());
		return getDirectURL("");
	}

	String getDirectURL(String uri) {
		return "redirect:" + Global.ADMIN_PATH + "/inventory/out/" + uri;
	}

	public void updateEmployee(HttpServletRequest request) {
		HttpSession session = request.getSession();
		Object attribute = session.getAttribute("employees");
		if (attribute == null) {
			session.setAttribute("employees",
					employeeDao.findListByStore(StoreUtils.getStore().getId(),Employee.STATUS_WORKING));
		} else if (attribute instanceof List<?>) {
			List<?> a = (List<?>) attribute;
			if (a.size() == 0) {
				session.setAttribute("employees", employeeDao
						.findListByStore(StoreUtils.getStore().getId(),Employee.STATUS_WORKING));
			}
		}
	}

	@RequestMapping(value = { "create" })
	public String inventoryOutCreate(InventoryOut inventoryOut,
			InQuery inQuery, HttpServletRequest request,
			HttpServletResponse response, Model model) {
		// 重新出库
		request.getSession().setAttribute(KEY_INVENTORY_OUT, inventoryOut);
		inventoryOut.setDateTime(DateUtils.getDate("yyyy-MM-dd HH:mm:ss"));
		model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);
		model.addAttribute(KEY_OUT_PRODUCT, new OutProduct());
		inventoryOut.setSystemProductList(getProducts(inventoryOut,
				StoreProduct.TYPE_SYS));
		inventoryOut.setStoreProductList(getProducts(inventoryOut,
				StoreProduct.TYPE_SELF));
		return getDirectURL("product/page");
	}

	/**
	 * Always, the data will be filled into StoreProduct, but the real data will
	 * be filled into Product, Then We should update the StoreProduct data
	 * correctly according to the product_type
	 * 
	 * @param outProduct
	 * @param inQuery
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = { "product/add" })
	public String outProductAdd(OutProduct outProduct, InQuery inQuery,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		InventoryOut inventoryOut = (InventoryOut) attribute;
		model.addAttribute("editInProduct", new OutProduct());
		model.addAttribute(KEY_OUT_PRODUCT, new OutProduct());
		model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);
		if (outProduct.getProduct() == null) {
			return getDirectURL("product/page");
		}
		Long id = outProduct.getProduct().getId();

		OutProduct real = new OutProduct();
		real.setAmount(outProduct.getAmount());
		// load the StoreProduct correctly by ID and update the amount
		StoreProduct product = storeProductService.get(id);
		real.setProduct(product);
		if (product.getProduct_type() == StoreProduct.TYPE_SYS) {
			real.setPrice(product.getProduct().getRetail_price()
					* real.getAmount());
			inventoryOut.getSystemProducts().add(real);
		} else {
			real.setPrice(product.getStoreSelfProduct().getRetail_price()
					* real.getAmount());
			inventoryOut.getStoreselfProducts().add(real);
		}

		return getDirectURL("product/page");
	}

	@RequestMapping(value = { "product/addpage" })
	public String inventoryOutProductAddPage(HttpServletRequest request,
			HttpServletResponse response, Model model) {
		InventoryOut inventoryout = (InventoryOut) request.getSession()
				.getAttribute(KEY_INVENTORY_OUT);
		model.addAttribute(KEY_OUT_PRODUCT, new OutProduct());
		model.addAttribute(KEY_INVENTORY_OUT, inventoryout);
		return URI_OUT_SYSTEM_PRODUCT_ADD_EDIT_PAGE;
	}

	/**
	 * Always, the data will be filled into StoreProduct, but the real data will
	 * be filled into Product, Then We should update the StoreProduct data
	 * correctly according to the product_type
	 * 
	 * @param outQuery
	 * @param editProduct
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping(value = { "product/edit" })
	public String outProductEdit(OutQuery outQuery, OutProduct editProduct,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		InventoryOut inventoryOut = (InventoryOut) attribute;
		String parameter = request.getParameter("id");
		List<OutProduct> storeselfProducts = inventoryOut
				.getStoreselfProducts();
		List<OutProduct> systemProducts = inventoryOut.getSystemProducts();
		if (parameter == null) {
			OutProduct edit = null;
			for (OutProduct outProduct : storeselfProducts) {
				if (outProduct.getProduct().getId().longValue() == editProduct
						.getProduct().getId().longValue()) {
					edit = outProduct;
					break;
				}
			}
			if (edit == null) {
				for (OutProduct outProduct : systemProducts) {
					if (outProduct.getProduct().getId().longValue() == editProduct
							.getProduct().getId().longValue()) {
						edit = outProduct;
						break;
					}
				}
			}
			edit.setAmount(editProduct.getAmount());
			if (edit.getProduct().getProduct_type() == StoreProduct.TYPE_SYS) {
				edit.setPrice(edit.getAmount()
						* edit.getProduct().getProduct().getRetail_price());
			} else {
				edit.setPrice(edit.getAmount()
						* edit.getProduct().getStoreSelfProduct()
								.getRetail_price());
			}
			// save
			model.addAttribute(KEY_OUT_PRODUCT, editProduct);
			model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);

			Page<OutProduct> page = new Page<OutProduct>(request, response);
			List<OutProduct> products = new ArrayList<OutProduct>();
			products.addAll(systemProducts);
			products.addAll(storeselfProducts);
			page.updatePage(products);
			model.addAttribute("page", page);
			return getDirectURL("product/page");
		} else {
			int id = Integer.parseInt(parameter);
			OutProduct edit = null;
			for (OutProduct outProduct : storeselfProducts) {
				if (outProduct.getProduct().getId().longValue() == id) {
					edit = outProduct;
					break;
				}
			}
			if (edit == null) {
				for (OutProduct outProduct : systemProducts) {
					if (outProduct.getProduct().getId().longValue() == id) {
						edit = outProduct;
						break;
					}
				}
			}
			editProduct = edit.copy();
			editProduct.setEditing(true);
			StoreSelfProduct storeSelfProduct = editProduct.getProduct()
					.getStoreSelfProduct();
			// if the type is StoreProduct.TYPE_SELF, value should be converted.
			if (editProduct.getProduct().getProduct_type() == StoreProduct.TYPE_SELF) {
				Product product = editProduct.getProduct().getProduct();
				if (product == null) {
					product = new Product();
					editProduct.getProduct().setProduct(product);
				}
				product.setName(storeSelfProduct.getName());
				product.setRetail_price(storeSelfProduct.getRetail_price());
				product.setSpec(storeSelfProduct.getSpec());
				if (product.getProductCategory() == null) {
					ProductCategory productCategory = new ProductCategory();
					product.setProductCategory(productCategory);
				}
				product.getProductCategory().setName(
						storeSelfProduct.getStoreSelfProductCategory()
								.getName());
			}
			// edit

			model.addAttribute(KEY_OUT_PRODUCT, editProduct);
			model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);
			return URI_OUT_SYSTEM_PRODUCT_ADD_EDIT_PAGE;
		}

	}

	private boolean remove(List<OutProduct> products, int id) {
		OutProduct outProduct = null;
		for (OutProduct p : products) {
			if (p.getProduct().getId().intValue() == id) {
				outProduct = p;
				break;
			}
		}
		if (outProduct != null) {
			return products.remove(outProduct);
		}
		return false;
	}

	@RequestMapping(value = { "product/delete" })
	public String outProductDelete(HttpServletRequest request,
			HttpServletResponse response, Model model) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		InventoryOut inventoryOut = (InventoryOut) attribute;
		String parameter = request.getParameter("id");
		List<OutProduct> storeselfProducts = inventoryOut
				.getStoreselfProducts();
		List<OutProduct> systemProducts = inventoryOut.getSystemProducts();
		if (parameter != null) {
			int id = Integer.parseInt(parameter);
			if (!remove(storeselfProducts, id)) {
				remove(systemProducts, id);
			}
		}

		return getDirectURL("product/page");
	}

	@RequestMapping(value = { "product/page" })
	public String outProductPage(OutQuery outQuery, HttpServletRequest request,
			HttpServletResponse response, Model model) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		InventoryOut inventoryOut = (InventoryOut) attribute;
		model.addAttribute("editInProduct", new OutProduct());
		model.addAttribute(KEY_OUT_PRODUCT, new OutProduct());
		model.addAttribute(KEY_INVENTORY_OUT, inventoryOut);
		Page<OutProduct> page = new Page<OutProduct>(request, response);
		page.updatePage(inventoryOut.getAll());
		model.addAttribute("page", page);
		return getURI_out_main();
	}

	@RequestMapping(value = { "product/save" })
	public String outProductSave(OutQuery outQuery, HttpServletRequest request,
			HttpServletResponse response, Model model,RedirectAttributes redirectAttributes) {
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		if(attribute==null){
			addMessage(redirectAttributes, "状态丢失");
			return  getDirectURL("");
		}
		InventoryOut saved = (InventoryOut) attribute;
		String parameter = request.getParameter("employee.id");
		saved.getEmployee().setId(Long.parseLong(parameter));
		String remark = request.getParameter("remark");
		saved.setRemark(remark);
		StoreInventoryOut inventoryOut = inventoryService.out(saved);
		request.getSession().removeAttribute(KEY_INVENTORY_OUT);
		
	    addMessage(redirectAttributes, "出货完成");
		return getDirectURL("detail?id="+inventoryOut.getId());
	}
	
	@RequestMapping(value = { "detail" })
	public String inventoryInDetail(HttpServletRequest request,
			HttpServletResponse response, Model model,
			RedirectAttributes redirectAttributes) {
		String id = request.getParameter("id");
		try {
			long parseInt = Integer.parseInt(id);
			// search details
			StoreInventoryOut inventoryout = inventoryOutDao.findOne(parseInt);
			List<StoreInventoryOutDetail> details = inventoryService.findOutDetails((int)parseInt);
			model.addAttribute("details", details);
			model.addAttribute("inventoryOut", inventoryout);
			return "modules/inventory/inventoryOutDetail";
		} catch (Exception e) {
			addMessage(redirectAttributes, "错误的出库查询请求");
			return getDirectURL("");
		}
	}


	String getURI_out_main() {
		return "modules/inventory/inventoryOutMain";
	}

	private boolean contains(List<Long> ids, Long id) {
		for (Long long1 : ids) {
			if (long1.equals(id)) {
				return true;
			}
		}
		return false;
	}

	public List<StoreProduct> getProducts(InventoryOut inventoryOut, int type) {
		List<StoreProduct> result = new ArrayList<StoreProduct>();
		result.addAll(storeProductService.findByStatus(type, -1));
		List<StoreProduct> remove = new ArrayList<StoreProduct>();
		for (StoreProduct product : result) {
			if (product.getAmount() < 1) {
				remove.add(product);
			}
		}
		result.removeAll(remove);
		remove.clear();
		StoreProduct temp;
		for (OutProduct outProduct : inventoryOut.getSystemProducts()) {
			temp = null;
			for (StoreProduct storeProduct : result) {
				if (outProduct.getProduct().getId().longValue() == storeProduct
						.getId().longValue()) {
					temp = storeProduct;
					break;
				}
			}
			if (temp != null) {
				result.remove(temp);
			}
		}
		for (OutProduct outProduct : inventoryOut.getStoreselfProducts()) {
			temp = null;
			for (StoreProduct storeProduct : result) {
				if (outProduct.getProduct().getId().longValue() == storeProduct
						.getId().longValue()) {
					temp = storeProduct;
					break;
				}
			}
			if (temp != null) {
				result.remove(temp);
			}
		}
		return result;
	}

	@ResponseBody
	@RequestMapping(value = "out/data/product")
	public String outProductDatas(@RequestParam(required = false) Long extId,
			HttpServletRequest request, HttpServletResponse response) {
		String typeStr = request.getParameter("type");
		int type = Integer.parseInt(typeStr);
		response.setContentType("application/json; charset=UTF-8");
		Set<Map<String, Object>> set = Sets.newHashSet();
		List<StoreProduct> storeProducts = storeProductService
				.findByStatus(type, -1);
		List<Long> added = new ArrayList<Long>();
		Object attribute = request.getSession().getAttribute(KEY_INVENTORY_OUT);
		InventoryOut inventoryOut = (InventoryOut) attribute;
		List<OutProduct> systemProducts = inventoryOut.getSystemProducts();
		for (OutProduct outProduct : systemProducts) {
			added.add(outProduct.getProduct().getId());
		}
		List<OutProduct> storeselfProducts = inventoryOut
				.getStoreselfProducts();
		for (OutProduct outProduct : storeselfProducts) {
			added.add(outProduct.getProduct().getId());
		}
		for (StoreProduct product : storeProducts) {
			if (product.getAmount() < 1) {
				// if no product left, continue
				continue;
			}
			if (contains(added, product.getId())) {
				// if added, continue
				continue;
			}
			Map<String, Object> map = Maps.newHashMap();
			map.put("id", product.getId());// here is store product ID\
			map.put("type", product.getProduct_type());
			if (product.getProduct_type() == StoreProduct.TYPE_SYS) {
				Product p = product.getProduct();
				map.put("category", p.getProductCategory().getName());
				map.put("name", p.getName());
				map.put("price", p.getRetail_price());
				map.put("spec", p.getSpec());
			} else {
				StoreSelfProduct p = product.getStoreSelfProduct();
				map.put("category", p.getStoreSelfProductCategory().getName());
				map.put("name", p.getName());
				map.put("price", p.getRetail_price());
				map.put("spec", p.getSpec());
			}
			map.put("amount", product.getAmount());
			set.add(map);
		}
		return JsonMapper.getInstance().toJson(set);
	}

	@RequestMapping(value = { "delete" })
	public String inventoryOutDelete(OutQuery outQuery,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		String parameter = request.getParameter("id");
		if (parameter != null) {
			int parseInt = Integer.parseInt(parameter);
			inventoryService.deleteInventoryOut(parseInt);
		}
		Page<StoreInventoryOut> page = new Page<StoreInventoryOut>(request,
				response);
		inventoryService.outQuery(page, outQuery);
		model.addAttribute("page", page);
		return "modules/inventory/inventoryOut";
	}

	@RequestMapping(value = { "query" })
	public String inventoryOutQuery(OutQuery outQuery,
			HttpServletRequest request, HttpServletResponse response,
			Model model) {
		return inventoryOut(outQuery, request, response, model);
	}
}
